﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;

namespace FXnaEngine
{
   public class FTransformComponent:FComponent
    {

       public FTransformComponent(FEntity parent)
           : base(parent)
       {
 

       }





        /// <summary>
        /// Position in the scene
        /// </summary>        
        public Vector3 Position
        {
            get { return this.position; }
            set
            {
                if (this.position != value)
                {
                    this.position = value;

                
                }
            }
        }


        private Vector3 position = Vector3.Zero;



        private Vector3 scale = Vector3.One;


       /// <summary>
       /// 缩放比例
       /// </summary>
        public Vector3 Scale
        {
            get { return scale; }
            set {

                if (this.scale!=value)
                {

                    scale = value; 
                    
                }
              
            
            }
        }


        private Vector3 rotation = Vector3.Zero;

        public Vector3 Rotation
        {
            get { return rotation; }
            set {

                if (this.rotation!=value)
                {

                    rotation = value;

                    this.orientation = Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z);

                    
                }
              
            
            
            }
        }


        Matrix orientation=Matrix.Identity;

        public Matrix Orientation
        {
            get { return orientation; }
            set { 
                

                orientation = value;

               
            
            }
        }


        Matrix worldMatrix = Matrix.Identity;

        public Matrix WorldMatrix
        {
            get { 

                

                //下用一个实时演算的版本吧
                //this.worldMatrix = Matrix.CreateFromYawPitchRoll(Rotation.Y, Rotation.X, Rotation.Z) * Matrix.CreateScale(this.scale) * Matrix.CreateTranslation(this.position.X, this.position.Y, this.position.Z) * Matrix.Identity;
                
                //return worldMatrix; 


                //有个问题很很郁闷，orientation,我这里到底想怎么用

                this.worldMatrix = this.orientation * Matrix.CreateScale(this.scale) * Matrix.CreateTranslation(this.position.X, this.position.Y, this.position.Z) * Matrix.Identity;

                return this.worldMatrix;



            
            }
          
        }



       



        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);


        }



        public override bool ExecuteMessage(IMessage message)
        {

            return false;
           
        }


        /// <summary>
        /// Points camera in direction of any position.
        /// </summary>
        /// <param name="targetPos">Target position for camera to face.</param>
        public void LookAt(Vector3 targetPos)
        {
            Vector3 newForward = targetPos - this.position;
            newForward.Normalize();

            Matrix rot = Matrix.Identity;
            rot.Forward = newForward;

            Vector3 referenceVector = Vector3.UnitY;

            // On the slim chance that the camera is pointer perfectly parallel with the Y Axis, we cannot
            // use cross product with a parallel axis, so we change the reference vector to the forward axis (Z).
            if (rot.Forward.Y == referenceVector.Y || rot.Forward.Y == -referenceVector.Y)
            {
                referenceVector = Vector3.UnitZ;
            }

            rot.Right = Vector3.Cross(rot.Forward, referenceVector);
            rot.Up = Vector3.Cross(rot.Right, rot.Forward);


            this.orientation =rot;



        }


        /// <summary>
        /// Points camera in direction of any position.
        /// </summary>
        /// <param name="x">X coordinate</param>
        /// <param name="y">Y coordinate</param>
        /// <param name="z">Z coordinate</param>
        public void LookAt(float x, float y, float z)
        {
            Vector3 newForward = new Vector3(x - this.position.X, y - this.position.Y, z - this.position.Z);
            newForward.Normalize();

            Matrix rot = Matrix.Identity;
            rot.Forward = newForward;

            Vector3 referenceVector = Vector3.UnitY;

            // On the slim chance that the camera is pointer perfectly parallel with the Y Axis, we cannot
            // use cross product with a parallel axis, so we change the reference vector to the forward axis (Z).
            if (rot.Forward.Y == referenceVector.Y || rot.Forward.Y == -referenceVector.Y)
            {
                referenceVector = Vector3.UnitZ;
            }

            rot.Right = Vector3.Cross(rot.Forward, referenceVector);
            rot.Up = Vector3.Cross(rot.Right, rot.Forward);


            this.orientation = rot; 

            //MsgSetRotation setRotMsg = ObjectPool.Aquire<MsgSetRotation>();
            //setRotMsg.Rotation = rot;
            //setRotMsg.UniqueTarget = this.uniqueID;
            //this.parentEntity.Game.SendMessage(setRotMsg);





        }





        /// <summary>
        /// Yaw this Entity around its own Up vector.
        /// </summary>
        /// <param name="yawAmount">Amount of radians to yaw.</param>
        public void Yaw(float yawAmount)
        {
            //MsgModifyRotation modRotMsg = ObjectPool.Aquire<MsgModifyRotation>();
            //modRotMsg.Rotation = Matrix.CreateFromAxisAngle(this.rotation.Up, yawAmount);
            //modRotMsg.UniqueTarget = this.uniqueID;
            //this.game.SendMessage(modRotMsg);


            this.orientation= this.orientation*Matrix.CreateFromAxisAngle(this.orientation.Up, yawAmount);

                 //this.rotation.tran Matrix.CreateFromAxisAngle(Vector3.Up, yawAmount);



        }

        /// <summary>
        /// Yaw this Entity around the world Up Vector (default is Y-axis).
        /// </summary>
        /// <param name="amount">Amount of radians to yaw.</param>
        public void YawAroundWorldUp(float amount)
        {
            //MsgModifyRotation modRotMsg = ObjectPool.Aquire<MsgModifyRotation>();
            //modRotMsg.Rotation = Matrix.CreateRotationY(amount);
            //modRotMsg.UniqueTarget = this.uniqueID;
            //this.game.SendMessage(modRotMsg);


            this.orientation=this.orientation*  Matrix.CreateRotationY(amount);



        }

        /// <summary>
        /// Pitch this Entity around its own Right vector.
        /// </summary>
        /// <param name="amount">Amount of radians to pitch.</param>
        public void Pitch(float amount)
        {
            //MsgModifyRotation modRotMsg = ObjectPool.Aquire<MsgModifyRotation>();
            //modRotMsg.Rotation = Matrix.CreateFromAxisAngle(this.rotation.Right, amount);
            //modRotMsg.UniqueTarget = this.uniqueID;
            //this.game.SendMessage(modRotMsg);

            this.orientation = this.orientation * Matrix.CreateFromAxisAngle(this.orientation.Right, amount);



        }

        /// <summary>
        /// Roll this Entity around its own Forward vector.
        /// </summary>
        /// <param name="amount">Amount of radians to roll.</param>
        public void Roll(float amount)
        {
            //MsgModifyRotation modRotMsg = ObjectPool.Aquire<MsgModifyRotation>();
            //modRotMsg.Rotation = Matrix.CreateFromAxisAngle(this.rotation.Forward, amount);
            //modRotMsg.UniqueTarget = this.uniqueID;
            //this.game.SendMessage(modRotMsg);


            this.orientation = this.orientation * Matrix.CreateFromAxisAngle(this.orientation.Forward, amount);


        }

        /// <summary>
        /// Strafe this Entity. Strafing moves the entity left or right by moving it along its Right vector.
        /// </summary>
        /// <param name="amount">Strafe distance, in world units.</param>
        public void Strafe(float amount)
        {
            //MsgModifyPosition setPositionMsg = ObjectPool.Aquire<MsgModifyPosition>();
            //setPositionMsg.Position = this.rotation.Right * amount;
            //setPositionMsg.UniqueTarget = this.uniqueID;
            //this.Game.SendMessage(setPositionMsg);


            this.Position += this.orientation.Right * amount;

        }

        /// <summary>
        /// Walk this Entity. Walking moves the entity forward or backward by moving it along its Forward vector.
        /// </summary>
        /// <param name="amount">Walking distance, in world units.</param>
        public void Walk(float amount)
        {
        //    MsgModifyPosition setPositionMsg = ObjectPool.Aquire<MsgModifyPosition>();
        //    setPositionMsg.Position = this.rotation.Forward * amount;
        //    setPositionMsg.UniqueTarget = this.uniqueID;
        //    this.Game.SendMessage(setPositionMsg);

            this.Position += this.orientation.Forward * amount;




        }

        /// <summary>
        /// Jump this Entity. Jumping moves the entity up or down (relative to itself) by moving it along its Up vector.
        /// </summary>
        /// <param name="amount">Strafe distance, in world units.</param>
        public void Jump(float amount)
        {

            //this.rotation.up


            //MsgModifyPosition setPositionMsg = ObjectPool.Aquire<MsgModifyPosition>();
            //setPositionMsg.Position = this.rotation.Up * amount;
            //setPositionMsg.UniqueTarget = this.uniqueID;
            //this.Game.SendMessage(setPositionMsg);


            this.Position += this.orientation.Up * amount;




        }

        /// <summary>
        /// Raise this Entity. Raising moves the entity up or down (relative to the world) by moving it along the world Up vector.
        /// </summary>
        /// <param name="amount">Rise distance, in world units.</param>
        public void Rise(float amount)
        {
            //MsgModifyPosition setPositionMsg = ObjectPool.Aquire<MsgModifyPosition>();
            //setPositionMsg.Position = Vector3.Up * amount;
            //setPositionMsg.UniqueTarget = this.uniqueID;
            //this.Game.SendMessage(setPositionMsg);


            //坑爹了，XNA系统默认的是y向上，我所参照的代码是z向上啊，到底怎么办啊


            //算了，下定决心了，还是改回Y向上吧，谁让底层XNA是Y向上呢，要不然，真的没办法，不能保证矩阵和向量的兼容的话，一切都是浮云啊

            //正好可以重新梳理一下地形的有关内容，以及移动变换



            this.Position += Vector3.Up * amount;



        }




    }
}
